#ifndef __IM_SLIST_H__
#define __IM_SLIST_H__

#include <im_base_types.h>

/**
 * @defgroup IMSList
 * @ingroup PrivateIMBusIME
 * @{
 */

/** @struct IMSList
 *  @brief Singly linked list
 */

IM_BEGIN_DECLS

typedef struct _IMSList IMSList;

struct _IMSList
{
    IMPointer data;
    IMSList *next;
};

/**
 * @brief Allocates space for one IMSList element.
 * @return a new IMSList element
 */
IMSList*    im_slist_alloc                  (void) IM_GNUC_WARN_UNUSED_RESULT;
/**
 * @brief Free all of the memory used by a IMSlist. The freed elements are returned to the slice allocator.
 * @param list an IMSList
 */
void        im_slist_free                   (IMSList           *list);
/**
 * @brief Free one IMSList element.
 * @param list an IMSList element
 */
void        im_slist_free_node              (IMSList           *list);
/**
 * @brief Adds a new element on to the end of the list.
 * @param list an IMSList
 * @param data the data for the new element
 * @return the new IMSList head
 */
IMSList*    im_slist_append                 (IMSList           *list,
                                             IMPointer          data) IM_GNUC_WARN_UNUSED_RESULT;
/**
 * @brief Adds a new element on to the start of the list.
 * @param list an IMSList
 * @param data the data of the new element
 * @return the new IMSList head
 */
IMSList*    im_slist_prepend                (IMSList           *list,
                                             IMPointer          data) IM_GNUC_WARN_UNUSED_RESULT;
/**
 * @brief Inserts a new element into the given position.
 * @param list an IMSList
 * @param data the data for the new element
 * @param position the position of the new element
 * @return the new IMSList head
 */
IMSList*    im_slist_insert                 (IMSList           *list,
                                             IMPointer          data,
                                             IMInt              position) IM_GNUC_WARN_UNUSED_RESULT;
/**
 * @brief Inserts a new element into the list, using the given comparison function to determine its position.
 * @param list an IMSList
 * @param data the data for the new element
 * @param func the comparison function
 * @return the new IMSList head
 */
IMSList*    im_slist_insert_sorted          (IMSList           *list,
                                             IMPointer          data,
                                             IMCompareFunc      func) IM_GNUC_WARN_UNUSED_RESULT;
/**
 * @brief Inserts a new element into the list, using the 
 * given comparison function to determine its position
 * @param list an IMSList
 * @param data the data for the new element
 * @param func the comparison function
 * @param user_data passed to comparison function
 * @return the new head of the IMSList
 */
IMSList*    im_slist_insert_sorted_with_data(IMSList           *list,
                                             IMPointer          data,
                                             IMCompareDataFunc  func,
                                             IMPointer          user_data) IM_GNUC_WARN_UNUSED_RESULT;
/**
 * @brief Inserts a new element before sibling containing data.
 * @param list an IMSList
 * @param sibling node to insert data before
 * @param data the data for the new element
 * @return the new IMSList head
 */
IMSList*    im_slist_insert_before          (IMSList           *slist,
                                             IMSList           *sibling,
                                             IMPointer          data) IM_GNUC_WARN_UNUSED_RESULT;
/**
 * @brief Adds the second IMSList onto the end of the first one.
 * @param list1 an IMSList
 * @param list2 another IMSList
 * @return the new IMSList head
 */
IMSList*    im_slist_concat                 (IMSList           *list1,
                                             IMSList           *list2) IM_GNUC_WARN_UNUSED_RESULT;
/**
 * @brief Removes an element from a IMSlist. If two elements contain the same data, 
 * only the first is removed. If none of the elements contain the data, the IMSlist is unchanged
 * @param list an IMSList
 * @param data
 * @return the new IMSList head
 */
IMSList*    im_slist_remove                 (IMSList           *list,
                                             IMConstPointer     data) IM_GNUC_WARN_UNUSED_RESULT;
/**
 * @brief Removes all list nodes with data equal to data.
 * @param list an IMSList
 * @param data
 * @return the new IMSList head
 */
IMSList*    im_slist_remove_all             (IMSList           *list,
                                             IMConstPointer     data) IM_GNUC_WARN_UNUSED_RESULT;
/**
 * @brief Removes an element from a IMSlist, without freeing the element. The removed element's
 * next link is set to NULL, so that it becomes a self contained list with one element.
 * @param list an IMSList
 * @return the new IMSList head
 */
IMSList*    im_slist_remove_link            (IMSList           *list,
                                             IMSList           *link) IM_GNUC_WARN_UNUSED_RESULT;
/**
 * @brief Deletes a node of list. Returns the new list head.
 * @param list an IMSList
 * @return the new IMSList head
 */
IMSList*    im_slist_delete_link            (IMSList           *list,
                                             IMSList           *link) IM_GNUC_WARN_UNUSED_RESULT;
/**
 * @brief Reverses an IMSList
 * @param list an IMSList
 * @return the new list head
 */
IMSList*    im_slist_reverse                (IMSList           *list) IM_GNUC_WARN_UNUSED_RESULT;
/**
 * @brief Clones an IMSList
 * @param list an IMSList
 * @return the new list head
 */
IMSList*    im_slist_clone                  (IMSList           *list) IM_GNUC_WARN_UNUSED_RESULT;
/**
 * @brief Gets the node of the IMSList at the given position
 * @param list an IMSList
 * @param n the node position
 * @return the node
 */
IMSList*    im_slist_nth                    (IMSList           *list,
                                             IMUInt             n);
/**
 * @brief Finds the element in an IMSList which contains the given data.
 * @param list an IMSList
 * @param data
 * @return node
 */
IMSList*    im_slist_find                   (IMSList           *list,
                                             IMConstPointer     data);
/**
 * @brief Finds the element in an IMSList, using a supplied function to find the desired element.
 * @param list an IMSList
 * @param data
 * @param func a comparison function
 * @return node
 */
IMSList*    im_slist_find_custom            (IMSList           *list,
                                             IMConstPointer     data,
                                             IMCompareFunc      func);
/**
 * @brief Gets the position of the given element in the IMSlist
 * @param list an IMSList
 * @param link an element
 * @return position of the elementthe new list head
 */
IMInt       im_slist_position               (IMSList           *list,
                                             IMSList           *link);
/**
 * @brief Gets the position of the element containing the given data
 * @param list an IMSList
 * @param data
 * @return the index of the first element which contains the data
 */
IMInt       im_slist_index                  (IMSList           *list,
                                             IMConstPointer     data);
/**
 * @brief Gets the position of the last element.
 * @param list an IMSList
 * @return last element of the IMSList
 */
IMSList*    im_slist_last                   (IMSList           *list);
/**
 * @brief Gets the length of the IMSList
 * @param list an IMSList
 * @return length
 */
IMUInt      im_slist_length                 (IMSList           *list);
/**
 * @brief calls a function for each element of the IMSList.
 * @param list an IMSList
 * @param functhe new list head
 * @param user_data passed to func
 */
void        im_slist_foreach                (IMSList           *list,
                                             IMFunc             func,
                                             IMPointer          user_data);
/**
 * @brief Sorts the IMSList with supplied comparison func.
 * @param list an IMSList
 * @param func comparison function
 * @return the sorted list head
 */
IMSList*    im_slist_sort                   (IMSList           *list,
                                             IMCompareFunc      compare_func) IM_GNUC_WARN_UNUSED_RESULT;
/**
 * @brief Sorts the IMSList with supplied comparison func and data.
 * @param list an IMSList
 * @param func comparison function
 * @param user_data data passed to compare func
 * @return the sorted list head
 */
IMSList*    im_slist_sort_with_data         (IMSList           *list,
                                             IMCompareDataFunc  compare_func,
                                             IMPointer          user_data) IM_GNUC_WARN_UNUSED_RESULT;
/**
 * @brief Gets the nth element's data.the new list head
 * @param list an IMSList
 * @param nth the position
 * @return the data of nth element
 */
IMPointer   im_slist_nth_data               (IMSList           *list,
                                             IMUInt             n);

/**
 * @brief A convenience macro to gets the next element in an IMSList.
 * @param list an IMSList element
 * @return the next element
 */
#define     im_slist_next(slist)            ((slist) ? (((IMSList *)(slist))->next) : 0)

IM_END_DECLS
/** @} */

#endif
/*
vi:ts=4:nowrap:ai:expandtab
*/
